import urllib
from api_server.utils import BaseResponse, ListResponse
from api_server.knowledge_base.utils import validate_kb_name
from api_server.knowledge_base.kb_service.base import KBServiceFactory
from api_server.db.repository.knowledge_base_repository import list_kbs_from_db, ListKbResponse
from configs import EMBEDDING_MODEL, logger, log_verbose
from fastapi import Body, Request, Path, Query
from api_server.auth_util import RedisUtil, get_user_info
from typing import Union
from api_server.db.repository.knowledge_base_repository import kb_exists_person, get_kb_from_id


def list_kbs(request: Request,
             kb_name: Union[str, None] = Query(description="知识库名称", default='', examples="samples")):
    # Get List of Knowledge Base
    user_info = get_user_info(request)
    return ListKbResponse(data=list_kbs_from_db(kb_name, user_info))


def create_kb(request: Request, knowledge_base_name: str = Body(..., examples=["samples"], description='只能为英文否则会获取不到'),
              vector_store_type: str = Body("pg", description="向量数据库类型"),
              kb_type: str = Body("public", description="知识库类型(public(公共),person(个人))"),
              kb_nickname: str = Body("", description="知识库昵称"),
              embed_model: str = Body(EMBEDDING_MODEL, description="分词模型"),
              ) -> BaseResponse:
    # Create selected knowledge base
    # 从redis中获取用户信息  个人创建的知识库不能超过2个
    user_info = get_user_info(request)
    if not validate_kb_name(knowledge_base_name):
        return BaseResponse(code=403, msg="Don't attack me")
    if knowledge_base_name is None or knowledge_base_name.strip() == "":
        return BaseResponse(code=404, msg="知识库名称不能为空，请重新填写知识库名称")

    kb = KBServiceFactory.get_service_by_name(knowledge_base_name)
    if kb is not None:
        return BaseResponse(code=404, msg=f"已存在同名知识库 {knowledge_base_name}")

    kb = KBServiceFactory.get_service(knowledge_base_name, vector_store_type, embed_model)

    # 添加用户信息
    if user_info:
        if kb_type == 'public' and not user_info.is_admin:
            return BaseResponse(code=401, msg=f"您无权限创建公共知识库 {knowledge_base_name}")
        create_user_id = user_info.user_id
        create_user_name = user_info.user_name
        kb.add_user_info(kb_type, create_user_id, create_user_name, kb_nickname=kb_nickname)
        status, k_name = kb_exists_person("person", create_user_id)
        if kb_type == 'person' and status:
            # 如果是个人知识库则只能添加一个
            return BaseResponse(code=404, msg=f"该用户已经存在知识库 {k_name}，不能再添加")
    else:
        kb.add_user_info(kb_type, None, None, kb_nickname=kb_nickname)
    try:
        kb.create_kb()
    except Exception as e:
        logger.exception(e)
        msg = f"创建知识库出错： {e}"
        logger.error(f'{e.__class__.__name__}: {msg}',
                     exc_info=e if log_verbose else None)
        return BaseResponse(code=500, msg=msg)

    return BaseResponse(code=200, msg=f"已新增知识库 {knowledge_base_name}")


def delete_kb(
        id: int = Body(..., examples=["1"], description="知识库主键id")
) -> BaseResponse:
    kb = KBServiceFactory.get_service_by_id(id)
    kb_model = get_kb_from_id(id)
    if kb_model is None:
        return BaseResponse(code=404, msg=f"未找到知识库 {id}")
    if kb_model.kb_type == 'public' and kb_model.kb_prop == 'sys':
        return BaseResponse(code=403, msg="公共知识库不能删除")
    if kb is None:
        return BaseResponse(code=404, msg=f"未找到知识库 {id}")
    knowledge_base_name = kb.kb_name
    if not validate_kb_name(knowledge_base_name):
        return BaseResponse(code=403, msg="Don't attack me")
    knowledge_base_name = urllib.parse.unquote(knowledge_base_name)

    kb = KBServiceFactory.get_service_by_name(knowledge_base_name)

    try:
        status = kb.clear_vs()
        status = kb.drop_kb()
        if status:
            return BaseResponse(code=200, msg=f"成功删除知识库 {knowledge_base_name}")
    except Exception as e:
        msg = f"删除知识库时出现意外： {e}"
        logger.error(f'{e.__class__.__name__}: {msg}',
                     exc_info=e if log_verbose else None)
        return BaseResponse(code=500, msg=msg)

    return BaseResponse(code=500, msg=f"删除知识库失败 {knowledge_base_name}")
